#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <XmlSerializer.h>

#include <data.h>
#include <dtwenty.h>
#include <characterclasstablemodel.h>

//#include <itemeditmodel.h>


#include <QFile>
#include <QFileDialog>
#include <QDebug>
#include <QMessageBox>
#include <QBuffer>
#include <QComboBox>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QListView>
#include <QTableView>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_model(new CollectionTreeModel(this))
{
    initData();
    initDTwenty();

    ui->setupUi(this);
    ui->actionZoomOut->setShortcut(QKeySequence("Ctrl+-")); //Set here because of Qt creator error
//    ui->groupBoxEdit->hide();

    // tree view
    ui->treeView->setModel(m_model);
    ui->treeView->header()->setResizeMode(QHeaderView::ResizeToContents);


    connect(ui->treeView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
            this,                           SLOT(onCurrentRowChanged(QModelIndex,QModelIndex)));

//    ui->treeViewEdit->setModel(new ItemEditModel(this));

    on_stackedWidget_currentChanged();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onMergeDoc()
{
    if (ui->stackedWidget->currentWidget() != ui->pageXml)
    {
        QBuffer b;
        XmlSerializer s;
        b.open(QBuffer::ReadWrite);
        s.serialize(m_root, &b);
        ui->plainTextEdit->setPlainText(b.data());

        return;
    }


    QBuffer b;
    XmlSerializer s;

    QByteArray a = ui->plainTextEdit->toPlainText().toAscii();

    b.setBuffer(&a);
    b.open(QBuffer::ReadWrite);

    Root* c = qobject_cast<Root*>(s.deserialize(&b));

    if (!c)
    {
        return;
    }

    if (!m_root.isNull())
    {
        m_root->deleteLater();
    }

    m_root = c;
    m_model->setRoot(m_root);
}


void MainWindow::onCloseDoc()
{
//    ui->groupBoxEdit->setTitle(tr("Item"));
    ui->groupBoxView->setTitle(tr("Campaign"));

    if (!m_root) return;

    if (m_root->changed())
    {

        int res = QMessageBox::question(this, tr("Save File?"), tr("Do you want to save file?"), QMessageBox::Yes|QMessageBox::No);
        if (res == QMessageBox::Yes)
        {
            on_actionSave_triggered();
        }
    }

    m_model->setRoot(0);
//    ItemEditModel* itemEdit = qobject_cast<ItemEditModel*>(ui->treeViewEdit->model());
//    itemEdit->setItem(0);

    m_root->deleteLater();
    m_root = 0;

    m_file.clear();
}

void MainWindow::onCurrentRowChanged(QModelIndex current, QModelIndex)
{
    ui->treeView->header()->setResizeMode(QHeaderView::ResizeToContents);
    m_model->refreshHeader(current);

    QModelIndex collIndex = collectionIndex(current);
//    ui->groupBoxEdit->setTitle(QString("%1 %2").arg(collIndex.data().toString()).arg(tr("Item")));

//    ItemEditModel* itemEdit = qobject_cast<ItemEditModel*>(ui->treeViewEdit->model());
//    if (!itemEdit) return;

//    Item* item = qobject_cast<Item*>(m_model->itemFromIndex(current));
//    itemEdit->setItem(item); // it's ok to set null, since it clears the model and view.
//    ui->treeViewEdit->header()->setResizeMode(QHeaderView::ResizeToContents);
//    ui->treeViewEdit->expandAll();

}

void MainWindow::closeEvent(QCloseEvent * e)
{
    onCloseDoc();
    QMainWindow::closeEvent(e);
}

QModelIndex MainWindow::collectionIndex(const QModelIndex &index) const
{
    AbstractModelItem* item = m_model->itemFromIndex(index);
    if (!item) return QModelIndex();

    QModelIndex collIndex = index;
    if (item->type() == ITEM_TYPE)
    {
        collIndex = index.parent();
    }

    return collIndex;
}


void MainWindow::on_actionNew_triggered()
{
    onCloseDoc();

    m_root = Campaign::create(this);

    m_model->setRoot(m_root);

    onMergeDoc();

    QHeaderView* header = ui->treeView->header();
    header->setResizeMode(QHeaderView::ResizeToContents);

    ui->treeView->setCurrentIndex(m_model->index(0, 0, QModelIndex()));
    ui->treeView->setFocus();

}

void MainWindow::on_actionOpen_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open"), QDir::currentPath(), tr("Xml Files (*.xml)"));

    if (fileName.isEmpty())
    {
        return;
    }

    QFile file(fileName);
    if (!file.open(QFile::ReadOnly))
    {
        QMessageBox::critical(this, tr("File Read Error"), file.errorString());
        return;
    }

    onCloseDoc();

    XmlSerializer s(this);

    m_root = qobject_cast<Root*>(s.deserialize(&file));


    ui->statusBar->showMessage(file.fileName());
    if (m_root.isNull())
    {
        QMessageBox::critical(this, tr("Deserialize Error"), tr("Failed to deserialize!"));
        return;
    }

    m_file = fileName;
    m_root->setParent(this);
    m_model->setRoot(m_root);

    onMergeDoc();


    QHeaderView* header = ui->treeView->header();
    header->setResizeMode(QHeaderView::ResizeToContents);

    ui->treeView->setCurrentIndex(m_model->index(0, 0, QModelIndex()));
    ui->treeView->setFocus();

    if (ui->stackedWidget->currentWidget() != ui->pageSheets)
    {
        return;
    }

    on_actionViewSheets_triggered();
}

void MainWindow::on_actionSave_As_triggered()
{
    if (m_root.isNull()) return;

    QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), QDir::currentPath(), tr("Xml Files (*.xml)"));
    if (fileName.isEmpty())
    {
        return;
    }

    m_file = fileName;
    on_actionSave_triggered();
}

void MainWindow::on_actionSave_triggered()
{
    if (m_file.isEmpty())
    {
        on_actionSave_As_triggered();
        return;
    }


    QFile file(m_file);
    if (file.exists())
    {
        file.remove();
    }

    if (!file.open(QFile::WriteOnly))
    {
        QMessageBox::critical(this, tr("File Write Error"), file.errorString());
        return;
    }

    onMergeDoc();

    XmlSerializer s(this);

    s.serialize(m_root, &file);
    m_root->onChanged(false);

    ui->statusBar->showMessage(file.fileName());
}

void MainWindow::on_actionQuit_triggered()
{
    close();
}


void MainWindow::on_actionRemove_triggered()
{
    QModelIndex index = ui->treeView->currentIndex();
    if (!index.isValid()) return;

    AbstractModelItem* item = m_model->itemFromIndex(index);
    if (!item) return;

    int type = QMetaType::type(item->metaObject()->className());

    if (type != ITEM_TYPE && type != CHARACTER_CLASS_TYPE) return;

    QModelIndex parent = index.parent();
    m_model->removeRows(index.row(),1, parent);
}

void MainWindow::on_actionAdd_triggered()
{
    QModelIndex collIndex = collectionIndex(ui->treeView->currentIndex());
    if (!collIndex.isValid())
    {
        return;
    }

    AbstractModelItem* parentItem = m_model->itemFromIndex(collIndex);
    if (!parentItem) return;

    int type = parentItem->type();
    int row = m_model->rowCount(collIndex);


    if (type == SKILLS_TYPE ||
        type == FEATS_TYPE ||
        type == SPECIALS_TYPE ||
        type == CLASS_SPECIALS_TYPE)
    {
        if (!m_model->insertRows(ITEM_TYPE, 1, collIndex))
        {
            return;
        }

        QModelIndex created = m_model->index(row, 0, collIndex);
        if (!created.isValid()) return;

        ui->treeView->scrollTo(created);
        ui->treeView->setCurrentIndex(created);

        on_actionEdit_Item_triggered();
    }
}


void MainWindow::on_actionAdd_Character_Class_triggered()
{
    QModelIndex start = m_model->index(0, 0, QModelIndex());
    QModelIndexList found = m_model->match(start, Qt::DisplayRole, "Character Classes", 1, Qt::MatchFixedString);
    if (found.isEmpty())
    {
        return;
    }


    m_model->insertRows(CHARACTER_CLASS_TYPE, 1, found.first());
}


void MainWindow::on_actionEdit_Item_triggered()
{
//    ui->groupBoxEdit->show();
//    QAbstractItemModel* model = ui->treeViewEdit->model();
//    QModelIndex index = model->index(0,0,QModelIndex());
//    ui->treeViewEdit->setCurrentIndex(index);
//    ui->treeViewEdit->edit(index);
}


void MainWindow::on_actionCloseEditor_triggered()
{
    ui->treeView->setFocus();
//    ui->groupBoxEdit->hide();
}



void MainWindow::on_actionZoomIn_triggered()
{
    QModelIndex collIndex = collectionIndex(ui->treeView->currentIndex());

    while (collIndex.parent().isValid())
    {
        collIndex = collIndex.parent();
    }

    ui->treeView->setRootIndex(collIndex);
    ui->groupBoxView->setTitle(collIndex.data(Qt::DisplayRole).toString());
}

void MainWindow::on_actionZoomOut_triggered()
{
    ui->treeView->setRootIndex(QModelIndex());
    ui->groupBoxView->setTitle(tr("Campaign"));
}

void MainWindow::on_actionViewCampaign_triggered()
{
    if (ui->stackedWidget->currentWidget() == ui->pageXml)
    {
        onMergeDoc();
    }

    ui->stackedWidget->setCurrentWidget(ui->pageView);


}

void MainWindow::on_actionViewSheets_triggered()
{
    if (ui->stackedWidget->currentWidget() == ui->pageXml)
    {
        onMergeDoc();
    }

    // remove old widgets
    for (int i = 0; i < ui->tabWidgetSheets->count(); i++)
    {
        QWidget* w = ui->tabWidgetSheets->widget(i);
        w->hide();
        ui->tabWidgetSheets->removeTab(i);
        w->deleteLater();
    }

    QModelIndex start = m_model->index(0, 0, QModelIndex());
    QModelIndexList classesIndexList = m_model->match(start, Qt::DisplayRole, "Character Classes", 1, Qt::MatchFixedString | Qt::MatchRecursive);
    if (classesIndexList.isEmpty())
    {
        ui->stackedWidget->setCurrentWidget(ui->pageSheets);
        return;
    }

    QModelIndex classesIndex = classesIndexList.first();
    CharacterClasses* classes = reinterpret_cast<CharacterClasses*>(classesIndex.internalId());
    if (!classes)
    {
        ui->stackedWidget->setCurrentWidget(ui->pageSheets);
        return;
    }

    foreach (CharacterClass* character, classes->findChildren<CharacterClass*>())
    {
        QTableView* view = new QTableView(this);
        ui->tabWidgetSheets->addTab(view, character->name());

        CharacterClassTableModel* characterModel = new CharacterClassTableModel(character, view);
        view->setModel(characterModel);

        QHeaderView* header = view->horizontalHeader();
        header->setResizeMode(QHeaderView::ResizeToContents);
        header->setStretchLastSection(true);
    }

    ui->stackedWidget->setCurrentWidget(ui->pageSheets);
}

void MainWindow::on_actionViewXml_triggered()
{
    if (ui->stackedWidget->currentWidget() == ui->pageXml)
    {
        return;
    }

    onMergeDoc();

    ui->stackedWidget->setCurrentWidget(ui->pageXml);
}

void MainWindow::on_stackedWidget_currentChanged(int index)
{
    Q_UNUSED(index);

    QWidget* page = ui->stackedWidget->currentWidget();
    ui->actionViewCampaign->setEnabled(page != ui->pageView);
    ui->actionViewSheets->setEnabled(page != ui->pageSheets);
    ui->actionViewXml->setEnabled(page != ui->pageXml);
}
